/*
PhysicsEngine.h
Physics Engine declaration

Project: surface-physics : http://code.google.com/p/surface-physics/

Description :This file declares the interface for the physics engine as a part of the Bump
plugin. The PhysicsEngine class maintains the entire physics world and allocates partitions
to bases, vessels etc. It will also be used to maintain large collision spaces temporarily
for collisions in outer space. The rigid body representing the hull of the vessel will be
created in the collision space to collide with other objects

Positions will be maintained in float range through use of a moving origin close to the
colliding region in Orbiter global co-ords and conversion of co-ords back and forth.

Written by Abhijit Nandy
License : Apache License 2.0

*/

#pragma once

#include "../Visualizer/GlutDemoApplication.h"

#include "LinearMath/btAlignedObjectArray.h"
#include "btBulletDynamicsCommon.h"
#include "../Visualizer/GlutStuff.h"

#include <list>



class btBroadphaseInterface;
class btCollisionShape;
class btOverlappingPairCache;
class btCollisionDispatcher;
class btConstraintSolver;
struct btCollisionAlgorithmCreateFunc;
class btDefaultCollisionConfiguration;

//For allowing Bump_BaseObject to register an external(to this class) render function
class Bump_BaseObject;
typedef std::list<Bump_BaseObject*> RenderObjectList;

//Viewer modes
enum PhysicsMode {
	SILENT,
	VISUALIZE,
	MESH_TEST,
	BASE_CONSTRUCTION
};

//Terrain types currently supported
enum TerrainType {
	PLANE,
	TRIMESH,
	BOX,
	MSH,
	ORULEX
};


#define NO_KEY -1


/*
 * --------------------------Orbiter Interface ----------------------------
 * Declare all globals in .cpp file as extern here, so they can be set from outside
 * Do not set any vales here as it will lead to 'multiple redefinitions' errors
 */

//These are declared in Bump module & is needed by the PhysicsEngine class
extern PhysicsMode mode;
extern DWORD baseCmd;
extern bool stepSim;


/* --------------------- End of Orbiter Interface ---------------------- */



const int MAX_RENDER_OBJECTS = 20;

/**
 * The physics engine class that steps physics and uses GLUT to visualize
 */
class PhysicsEngine : public GlutDemoApplication
{

	//General Physics world variables	
	class btBroadphaseInterface*	m_overlappingPairCache;
	class btCollisionDispatcher*	m_dispatcher;
	class btConstraintSolver*	m_constraintSolver;
	class btDefaultCollisionConfiguration* m_collisionConfiguration;
	class btTriangleIndexVertexArray*	m_indexVertexArrays;
	btVector3*	m_vertices;

	btCollisionShape	*groundShape, *supportPlaneShape;
	btRigidBody* groundRigidBody;




	//Camera control
	btScalar	m_cameraHeight;
	btScalar	m_minCameraDistance;
	btScalar	m_maxCameraDistance;




public:

	//Needs to be public for the MSH importer
	btAlignedObjectArray<btCollisionShape*> m_collisionShapes;

	//The current body in focus : shown when F10 is pressed
	static btRigidBody* focusBody;

	/* The list of base objects whose renderme() should be called to draw additional shapes
	 * not in the dynamics world(like wheels of a raycast vehicle)
	 * A list is more efficient as objects might de-register mid-sim, causing deletion from list middle.
	 */
	RenderObjectList renderObjList;
	RenderObjectList::iterator renderObjIter;

	//External rendering object registration
	void addExternalRenderObject(Bump_BaseObject *bbObj)
	{ renderObjList.push_back(bbObj); }

	//External rendering object de-registration, can be used if a base object has requested
	//rendering but is being removed mid-sim, can be called from its destructor.
	//STL guarantees that if external list iterators are being maintained to the list then
	//they wont be invalidated even if some element before them was removed.
	int removeExternalRenderObject(RenderObjectList::iterator pos)
	{ renderObjList.erase(pos); }




	PhysicsEngine();
	virtual ~PhysicsEngine();

	void	initPhysics();
	void	exitPhysics();
	void 	getTransforms(void);
	void 	setTransforms(void);

	void clientMoveAndDisplay();
	void displayCallback();
	void renderme();
	void WMCloseFuncCallback();
	void clientResetScene();

	//Very basic camera following the vehicle
	void updateCamera();

	void specialKeyboard(int key, int x, int y);
	void specialKeyboardUp(int key, int x, int y);

	//Used by defineGround() which is called externally by BulletBase
	void addSupportPlane(void);

	//Orbiter msh tools
	btRigidBody* addOrbiterMshDynamic(char *fileName, btVector3& offset);
	btRigidBody* addOrbiterMshStatic(char *fileName, btVector3& offset);
	btCollisionShape* importMsh(char *fileName);

	//Triangle mesh, can be removed
	btCollisionShape* defineTriMeshShape(void);
	void defineVehicleTrain(void);
	int  defineGround(TerrainType terrainType);
	


	static DemoApplication* Create()
	{
		PhysicsEngine* demo = new PhysicsEngine;
		demo->myinit();
		demo->initPhysics();
		return demo;
	}

	btDynamicsWorld* getDynamicWorld(void)
	{ return m_dynamicsWorld; }

	GL_ShapeDrawer* getShapeDrawer(void)
		{ return m_shapeDrawer; }


	btAlignedObjectArray<btCollisionShape*>* getCollisionShapesArray(void)
	{ return &m_collisionShapes; }

	
};


